/**
 * @Description PointClearTimer.java
 * @author xu_cc [18724000100@163.com]
 * @date 创建时间：2017年10月26日 上午11:05:34
 */
package com.solution.admin.point.timer;

import java.math.BigDecimal;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import com.solution.admin.point.constants.PointConstants.PointClearRuleType;
import com.solution.admin.point.constants.PointConstants.PointOperateFlag;
import com.solution.admin.point.constants.PointConstants.PointOperateType;
import com.solution.admin.point.constants.PointConstants.TimerSwitch;
import com.solution.admin.point.entity.PointEntity;
import com.solution.admin.point.entity.PointRuleEntity;
import com.solution.admin.point.service.PointLogService;
import com.solution.admin.point.service.PointRuleService;
import com.solution.admin.point.service.PointService;
import com.solution.common.config.PublicConfigUtil;
import com.solution.common.utils.DateUtils;
import com.solution.common.utils.json.JSONUtils;

/**
 * 积分清零任务（根据积分清零规则执行）
 * 
 * @author xu_cc
 * @date 创建时间：2017年10月26日 上午11:06:18
 */
@Component
public class PointClearTimer implements InitializingBean {

    private Logger logger = LoggerFactory.getLogger(PointClearTimer.class);

    @Autowired
    PointRuleService pointRuleService;

    @Autowired
    PointService pointService;

    @Autowired
    PointLogService pointLogService;

    /** 期初积分生成任务执行开关 key */
    static final String POINT_CLEAR_SWITCH = "timer.pointClearRule.switch";
    /** 期初积分生成任务执行日期 key */
    static final String POINT_CLEAR_TIME = "timer.pointClearRule.time";

    @Override
    public void afterPropertiesSet() throws Exception {
        // 获取任务开关
        String timerSwitch = PublicConfigUtil.readConfig(POINT_CLEAR_SWITCH);
        if (TimerSwitch.OFF.equals(timerSwitch)) {
            // 如果开关关闭，则不执行定时任务
            return;
        } else if (TimerSwitch.ON.equals(timerSwitch)) {
            /**
             * 线程一：每月1号凌晨，生成所有客户的期初积分（所有客户积分）
             * */
            // 一天的毫秒数
            long oneDay = 24 * 60 * 60 * 1000;
            String timer = PublicConfigUtil.readConfig(POINT_CLEAR_TIME);// 每天几点执行
            // 计算初始延迟的毫秒数
            long initDelay = DateUtils.getTimeMillis(timer) - System.currentTimeMillis();
            /* 线程实现 */
            Runnable runableOfClear = new Runnable() {
                @Override
                public void run() {
                    logger.error("***************** 开始定时任务：积分清零 *******************");
                    try {
                        // 当前月份日期
                        SimpleDateFormat dayFormat = new SimpleDateFormat("MMdd");
                        String day = dayFormat.format(new Date());
                        PointRuleEntity pointRule = pointRuleService.getEnablePointRule();
                        // 获取积分到期日
                        if (day.equals(pointRule.getExpireDate())) {
                            if (PointClearRuleType.RULE_KEEP.getCode().equals(pointRule.getRuleType())) {
                                /**
                                 * 规则1、到期全部保留
                                 * */
                                // 那就啥也不做
                                logger.error("无需操作。积分清零规则：" + PointClearRuleType.RULE_KEEP.getName());
                            } else if (PointClearRuleType.RULE_CLEAR.getCode().equals(pointRule.getRuleType())) {
                                /**
                                 * 规则2、到期全部清零 
                                 * */
                                logger.error("积分清零规则：{}", PointClearRuleType.RULE_CLEAR.getName());
                                // 获取系统当前所有客户的积分信息列表
                                List<PointEntity> pointList = pointService.listPoint(new HashMap<String, Object>());
                                if (null != pointList && pointList.size() > 0) {
                                    // 循环清空所有客户积分情况
                                    // 到期限清零
                                    String optType = PointOperateType.OPT_EXP_CLEAR.getCode();
                                    // 到期限清零
                                    int optFlag = PointOperateFlag.FLAG_MINUS.getId();
                                    for (PointEntity point : pointList) {
                                        try {
                                            int rows = pointService.doOperatePointCommon(point.getCustomerId(), optFlag, optType, point.getPoint(),
                                                    PointOperateType.OPT_EXP_CLEAR.getName(), null, null, "system", true);
                                            String result = (rows > 0 ? "成功" : "失败");
                                            logger.error("客户编号：{},客户名称{},客户号码：{} 积分到期清零 {}", point.getCustomerId(), point.getCustomerName(),
                                                    point.getMobile(), result);
                                        } catch (Exception e) {
                                            e.printStackTrace();
                                            logger.error("客户编号：{},客户名称{},客户号码：{} 积分到期清零异常", point.getCustomerId(), point.getCustomerName(),
                                                    point.getMobile());
                                            continue;
                                        }
                                    }
                                } else {
                                    logger.error("没有需要清空的积分信息！");
                                }
                            } else if (PointClearRuleType.RULE_MONTH_THREE.getCode().equals(pointRule.getRuleType())) {
                                /**
                                 * 规则3、到期保留近三月积分
                                 *  */
                                logger.error("积分清零规则：{}", PointClearRuleType.RULE_MONTH_THREE.getName());
                                // 只需要保留年月日
                                SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd");
                                Calendar calendar = Calendar.getInstance();
                                // 当前日期
                                Date currentDate = calendar.getTime();
                                // 3个月前
                                calendar.add(Calendar.MONTH, -3);
                                Date threeMonthBefore = calendar.getTime();
                                Map<String, Object> paramMap = new HashMap<String, Object>();
                                paramMap.put("beginTime", dateFormat.format(threeMonthBefore) + " 00:00:00");
                                paramMap.put("endTime", dateFormat.format(currentDate) + " 23:59:59");
                                // 获取系统当前所有客户的积分信息列表
                                List<PointEntity> pointList = pointService.listPoint(new HashMap<String, Object>());
                                if (null != pointList && pointList.size() > 0) {
                                    // 循环清空所有客户积分情况
                                    // 到期限清零
                                    String optType = PointOperateType.OPT_EXP_CLEAR.getCode();
                                    // 到期限清零
                                    int optFlag = PointOperateFlag.FLAG_MINUS.getId();
                                    for (PointEntity point : pointList) {
                                        try {
                                            // 操作积分
                                            BigDecimal optPoint = BigDecimal.ZERO;
                                            // 当前客户积分
                                            BigDecimal currPoint = point.getPoint();
                                            // 获取客户近3月所得积分
                                            paramMap.put("customerId", point.getCustomerId());
                                            BigDecimal threeTotalPoint = pointLogService.getTotalByCustomerIdInTime(paramMap);
                                            // 如果近3月所得积分大于当前积分，那么则无需扣减积分（积分被花了呗，怎么可能再送呢）
                                            // 如果金3月所得积分小于当前积分，则扣除多余部分积分
                                            // 结果是:-1 小于,0 等于,1 大于
                                            if (threeTotalPoint.compareTo(currPoint) == -1) {
                                                // 计算多余积分作为需要扣减的积分
                                                optPoint = currPoint.subtract(threeTotalPoint);
                                                int rows = pointService.doOperatePointCommon(point.getCustomerId(), optFlag, optType, optPoint,
                                                        PointOperateType.OPT_EXP_CLEAR.getName(), null, null, "system", true);
                                                String result = (rows > 0 ? "成功" : "失败");
                                                logger.error("客户编号：{},客户名称{},客户号码：{}，需要扣减积分：{} 积分到期清零 {}", point.getCustomerId(),
                                                        point.getCustomerName(), optPoint, point.getMobile(), result);
                                            } else {
                                                logger.error("客户编号：{},客户名称{},客户号码：{} 无需扣减积分。当前积分：{}，近3月所得积分：{}", point.getCustomerId(),
                                                        point.getCustomerName(), point.getMobile(), currPoint, threeTotalPoint);
                                            }
                                        } catch (Exception e) {
                                            logger.error("客户编号：{},客户名称{},客户号码：{} 积分到期清零异常", point.getCustomerId(), point.getCustomerName(),
                                                    point.getMobile());
                                            e.printStackTrace();
                                            continue;
                                        }
                                    }
                                } else {
                                    logger.error("没有需要清空的积分信息！");
                                }
                            } else {
                                logger.error("未知的积分清零规则：" + JSONUtils.toJsonString(pointRule));
                            }
                        } else {
                            // 还没到时间
                            logger.error("积分到期日：" + pointRule.getExpireDate() + " 今天日期：" + day);
                        }
                    } catch (Exception e) {
                        e.printStackTrace();
                    }
                    logger.error("***************** 积分清零定时任务结束 *******************");
                }
            };
            ScheduledExecutorService service = Executors.newSingleThreadScheduledExecutor();
            // 第二个参数为首次执行的延时时间，第三个参数为定时执行的间隔时间
            service.scheduleAtFixedRate(runableOfClear, initDelay, oneDay, TimeUnit.MILLISECONDS);
        } else {
            logger.error("未知的定时任务开关值，请输入 on/off ");
        }
    }
}
